package com.easyapi.server.service.api.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easyapi.common.base.UserTokenThreadHolder;
import com.easyapi.common.enums.StatusCode;
import com.easyapi.common.enums.project.ProjectStatus;
import com.easyapi.common.exception.BizException;
import com.easyapi.common.param.project.AddProjectParam;
import com.easyapi.common.param.project.ProjectPageParam;
import com.easyapi.common.utils.ResultUtils;
import com.easyapi.common.vo.datasource.DataSourceListVo;
import com.easyapi.common.vo.project.ProjectListVo;
import com.easyapi.common.vo.project.ProjectVo;
import com.easyapi.common.vo.user.ApiCenterUserVo;
import com.easyapi.dao.entity.api.ApiCenterDatasource;
import com.easyapi.dao.entity.api.ApiCenterProject;
import com.easyapi.dao.entity.api.ApiCenterProjectDatasource;
import com.easyapi.dao.entity.user.ApiCenterUser;
import com.easyapi.dao.mapper.api.ApiCenterProjectMapper;
import com.easyapi.server.service.api.DataSourceService;
import com.easyapi.server.service.api.ProjectDatasourceService;
import com.easyapi.server.service.api.ProjectService;
import com.easyapi.server.service.user.UserService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author javadadi
 */
@Service
public class ProjectServiceImpl extends ServiceImpl<ApiCenterProjectMapper, ApiCenterProject> implements ProjectService {
    @Resource
    private ApiCenterProjectMapper projectMapper;

    @Resource
    private UserService userService;

    @Resource
    private DataSourceService dataSourceService;

    @Resource
    private ProjectDatasourceService projectDatasourceService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveProject(AddProjectParam param) {
        String id = param.getId();
        String projectName = param.getProjectName();
        String projectDesc = param.getProjectDesc();
        if (StringUtils.isAnyBlank(projectName, projectDesc)) {
            throw new BizException(StatusCode.PARAMS_ERROR);
        }
        ApiCenterUserVo currentUser = UserTokenThreadHolder.getCurrentUser();
        if (Objects.isNull(currentUser)) {
            throw new BizException(StatusCode.NO_LOGIN);
        }
        // todo 服务编排
        Integer openOrchestration = param.getOpenOrchestration();
        boolean isUpdate = Objects.nonNull(id);
        ApiCenterProject project = null;
        if (isUpdate) {
            project = getById(id);
            if (Objects.isNull(project)) {
                throw new BizException(StatusCode.NO_SUCH_PROJECT);
            }
            List<String> projectNames = projectMapper.listAllProjectNames();
            if (projectNames.contains(projectName)) {
                throw new BizException(StatusCode.REPEAT_PROJECT_NAME);
            }
            project.setProjectName(projectName);
            project.setProjectDesc(projectDesc);
            project.setUpdateBy(currentUser.getId());
        } else {
            project = new ApiCenterProject();
            project.setProjectName(projectName);
            project.setProjectDesc(projectDesc);
            project.setOpenOrchestration(openOrchestration);
            project.setCreateBy(currentUser.getId());
            project.setUpdateBy(currentUser.getId());
            project.setStatus(ProjectStatus.PROJECT_INIT.getCode());
        }
        project.setStatus(ProjectStatus.PROJECT_USING.getCode());
        this.saveOrUpdate(project);
        return true;
    }

    @Override
    public Page<ProjectVo> page(ProjectPageParam param) {
        String projectName = param.getProjectName();
        Integer status = param.getStatus();
        Integer openOrchestration = param.getOpenOrchestration();
        Long size = param.getSize();
        Long current = param.getCurrent();
        Page<ApiCenterProject> page = new Page<>(current, size);
        LambdaQueryWrapper<ApiCenterProject> wrapper = new LambdaQueryWrapper<ApiCenterProject>()
                .like(StringUtils.isNotEmpty(projectName), ApiCenterProject::getProjectName, projectName)
                .eq(Objects.nonNull(status), ApiCenterProject::getStatus, status)
                .like(Objects.nonNull(openOrchestration), ApiCenterProject::getOpenOrchestration, openOrchestration);
        Page<ApiCenterProject> projectPage = page(page, wrapper);
        List<ProjectVo> vos = projectPage.getRecords().stream().map(project -> {
            Long createBy = project.getCreateBy();
            Long updateBy = project.getUpdateBy();
            ApiCenterUser createUser = userService.getById(createBy);
            ApiCenterUser updateUser = userService.getById(updateBy);
            ProjectVo build = ProjectVo.builder()
                    .id(project.getId())
                    .projectName(project.getProjectName())
                    .projectDesc(project.getProjectDesc())
                    .status(project.getStatus())
                    .openOrchestration(project.getOpenOrchestration())
                    .createAt(project.getCreateAt())
                    .updateAt(project.getUpdateAt())
                    .createBy(Objects.nonNull(createUser) ? createUser.getId() : 0L)
                    .createUserName(Objects.nonNull(createUser) ? createUser.getUserName() : "")
                    .updateBy(Objects.nonNull(updateUser) ? updateUser.getId() : 0L)
                    .updateUserName(Objects.nonNull(updateUser) ? updateUser.getUserName() : "")
                    .build();
            return build;
        }).collect(Collectors.toList());
        Page<ProjectVo> voPage = new Page<>(projectPage.getCurrent(), projectPage.getSize(), projectPage.getTotal());
        voPage.setRecords(vos);
        return voPage;
    }

    /**
     * 引用数据源
     */
    @Override
    public boolean addProjectDatasource(Long projectId, Long datasourceId) {
        ApiCenterUserVo currentUser = UserTokenThreadHolder.getCurrentUser();
        ApiCenterProject project = this.getById(projectId);
        if (Objects.isNull(project)) {
            throw new BizException(StatusCode.NO_SUCH_PROJECT);
        }
        ApiCenterDatasource datasource = dataSourceService.getById(datasourceId);
        if (Objects.isNull(datasource)) {
            throw new BizException(StatusCode.NO_SUCH_DATASOURCE);
        }
        ApiCenterProjectDatasource apiCenterProjectDatasource = new ApiCenterProjectDatasource();
        apiCenterProjectDatasource.setProjectId(projectId);
        apiCenterProjectDatasource.setDatasourceId(datasourceId);
        apiCenterProjectDatasource.setCreateBy(currentUser.getId());
        apiCenterProjectDatasource.setUpdateBy(currentUser.getId());
        projectDatasourceService.save(apiCenterProjectDatasource);
        return true;
    }

    /**
     * 取消引用数据源
     */
    @Override
    public boolean removeProjectDatasource(Long projectId, Long datasourceId) {
        //TODO api 正在使用的数据源不能够删除引用
        ApiCenterProjectDatasource datasource = projectDatasourceService.getByProjectIdAndDatasourceId(projectId, datasourceId);
        if (Objects.isNull(datasource)) {
            throw new BizException(StatusCode.NO_SUCH_DATASOURCE);
        }
        projectDatasourceService.removeById(datasource.getId());
        return true;
    }



    /**
     * 获取项目列表
     * @param projectName
     * @return
     */
    @Override
    public List<ProjectListVo> listProject(String projectName) {
        LambdaQueryWrapper<ApiCenterProject> wrapper = new LambdaQueryWrapper<ApiCenterProject>()
                .like(StringUtils.isNotBlank(projectName), ApiCenterProject::getProjectName, projectName);
        List<ApiCenterProject> list = list(wrapper);
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }
        List<ProjectListVo> vos = list.stream().map(m -> {
            ProjectListVo build = ProjectListVo
                    .builder()
                    .id(m.getId())
                    .projectName(m.getProjectName())
                    .projectDesc(m.getProjectDesc())
                    .build();
            return build;
        }).collect(Collectors.toList());
        return vos;
    }

}
